<template>
  <div class="app-container">
    <el-card shadow="never">
      <template #header>
        <el-button
          type="danger"
          size="default"
          v-hasPerm="['sys:file:delete']"
          :disabled="deleteFlg"
          @click="deleteFiles"
          >删除
        </el-button>
        <el-button type="primary" size="default" @click="uploadDialog = true">
          上传
        </el-button>
        <el-button
          type="success"
          size="default"
          :disabled="deleteFlg"
          v-hasPerm="['sys:file:download']"
          @click="downLoadZip"
        >
          下载
        </el-button>
      </template>
      <el-table
        :data="fileList"
        style="width: 100%"
        row-key="id"
        border
        v-loading="loading"
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="50" />
        <el-table-column prop="name" label="文件名" width="200" />
        <el-table-column prop="url" label=" 文件路径" />
        <el-table-column label="文件类型">
          <template #default="scope">
            <el-tag type="success" v-if="!scope.row.dir"> 文件 </el-tag>
            <el-tag type="info" v-if="scope.row.dir">目录</el-tag>
          </template>
        </el-table-column>
        <el-table-column label=" 操作">
          <template #default="scope">
            <el-button
              type="primary"
              link
              size="small"
              v-if="!scope.row.dir"
              @click="showPicture(scope.row)"
            >
              <el-icon><Picture /></el-icon>
              预览
            </el-button>
            <el-button
              type="primary"
              link
              size="small"
              v-if="!scope.row.dir"
              v-hasPerm="['sys:file:download']"
              @click="downloadFile(scope.row)"
            >
              <el-icon><Download /></el-icon>
              下载
            </el-button>
            <el-button
              type="primary"
              link
              size="small"
              v-if="!scope.row.dir"
              v-hasPerm="['sys:file:delete']"
              @click="deleteFileByFileName(scope.row)"
              ><i-ep-delete />
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <el-dialog title="图片预览" v-model="dialogVisible">
      <el-image :src="imgUrl" />
    </el-dialog>
    <el-dialog title="文件上传" v-model="uploadDialog">
      <el-upload
        class="upload-demo"
        drag
        multiple
        ref="uploadRef"
        accept=".jpg,.jpeg,.png"
        list-type="picture"
        :file-list="uploadFileList"
        :auto-upload="false"
        :before-upload="beforeUpload"
        :on-change="handleChange"
        :on-remove="handleRemove"
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">拖动文件到这里或者<em>点击上传</em></div>
      </el-upload>
      <el-button
        type="success"
        size="default"
        @click="uploadFileToMinio"
        v-if="uploadFlg"
        >上传文件到服务器</el-button
      >
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import {
  deleteFilesApi,
  deleteMinioFileApi,
  downLoadZipApi,
  downloadMinioFileApi,
  fetchMinioFileListApi,
  uploadFilesApi,
} from "@/api/file";
import { FileInfo, FileTreeChildrenList, FileTreeList } from "@/api/file/types";
import { UploadFile, UploadProps, UploadRawFile } from "element-plus";

const dialogVisible = ref(false);
const uploadDialog = ref(false);
const imgUrl = ref("");
const loading = ref(false);
const uploadRef = ref();
const fileList = ref<FileTreeList[]>();
const uploadFileList = ref<UploadFile[]>([]);
// 用于存放选中的文件名
let fileNames = new Array<string>();
// 控制删除按钮的状态
let deleteFlg = ref(true);
let uploadFlg = ref(false);

/**
 * 图片预览
 * @param row 当前行的文件信息
 */
const showPicture = (row: FileInfo) => {
  imgUrl.value = row.url.replace("minio", "localhost");
  dialogVisible.value = true;
};

/**
 * 根据文件名删除文件
 * @param row 当前行的文件信息
 */
const deleteFileByFileName = (row: FileTreeChildrenList) => {
  ElMessageBox.confirm("确认删除当前图片?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(function () {
    loading.value = true;
    if (row.fullPath) {
      deleteMinioFileApi(row.fullPath)
        .then(() => {
          ElMessage.success("删除成功");
          getFileList();
        })
        .finally(() => {
          loading.value = false;
        });
    }
  });
};

// 获取 Minio 文件列表
const getFileList = () => {
  loading.value = true;

  fetchMinioFileListApi()
    .then(({ data }) => {
      fileList.value = data;
    })
    .finally(() => {
      loading.value = false;
    });
};

// 批量选中文件
const handleSelectionChange = (val: FileTreeList[]) => {
  fileNames = [];
  for (const fileInfo of val) {
    if (fileInfo.dir) {
      continue;
    }
    if (fileInfo.fullPath) {
      fileNames.push(fileInfo.fullPath);
    }
  }

  fileNames.length > 0 ? (deleteFlg.value = false) : (deleteFlg.value = true);
};

// 批量删除文件
const deleteFiles = () => {
  ElMessageBox.confirm("确认删除当前选中的图片?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(function () {
    loading.value = true;
    if (fileNames) {
      deleteFilesApi(fileNames)
        .then(() => {
          ElMessage.success("删除成功");
          getFileList();
        })
        .finally(() => {
          loading.value = false;
        });
    }
  });
};

// 文件下载
const downloadFile = (row: FileTreeChildrenList) => {
  if (row.fullPath) {
    downloadMinioFileApi(row.fullPath).then(() => {
      ElMessage.success("下载成功");
    });
  }
};

// 文件上传到服务器
const uploadFileToMinio = () => {
  // 上传前对文件类型进行检查
  for (const file of uploadFileList.value) {
    let checkStatus = beforeUpload(file.raw!);
    if (!checkStatus) {
      return;
    }
  }
  //  调用上传文件 API，实现文件批量上传
  uploadFilesApi(uploadFileList.value).then(({ data }) => {
    if (data.length > 0) {
      ElMessage.success("上传成功");
      uploadDialog.value = false;
      uploadRef.value.clearFiles();
      // 清空上传文件列表
      uploadFileList.value.splice(0, uploadFileList.value.length);
      // 隐藏上传按钮
      uploadFlg.value = false;
      // 重新获取文件列表
      getFileList();
    }
  });
};

// 上传前的验证逻辑
const beforeUpload = (rawFile: UploadRawFile) => {
  const isJPGorPNG =
    rawFile.type === "image/jpeg" || rawFile.type === "image/png";
  const isLt500K = rawFile.size / 1024 < 500;

  if (!isJPGorPNG) {
    ElMessage.error("只能上传 JPG/PNG 格式的图片，请检查上传的文件类型。");
  }
  if (!isLt500K) {
    ElMessage.error("图片大小不能超过 500KB");
  }

  return isJPGorPNG && isLt500K;
};

// 文件选中状态发生改变时候的处理
const handleChange = (file: UploadFile) => {
  // 判断文件列表中是否存在该文件，不存在则添加
  uploadFileList.value = addUniqueObjectByKey(uploadFileList.value, file);
  // 如果文件列表不为空，则上传服务器按钮显示
  if (uploadFileList.value.length > 0) {
    uploadFlg.value = true;
  }
};

// 判断相同文件名的文件是否重复添加
const addUniqueObjectByKey = (fileList: UploadFile[], file: UploadFile) => {
  if (!Array.isArray(fileList) || typeof file !== "object" || file === null) {
    return fileList;
  }

  // 使用 some 方法来检查是否已存在具有相同 key 的对象
  if (fileList.some((item) => item.name === file.name)) {
    // 如果已存在，则不添加并返回原数组
    return fileList;
  }

  // 如果不存在，则将新对象添加到数组中
  fileList.push(file);
  return fileList;
};

// 从文件列表中移除文件的处理
const handleRemove: UploadProps["onRemove"] = (uploadFile) => {
  // 将对应文件名的文件从文件列表中删除
  uploadFileList.value = uploadFileList.value.filter(
    (item) => item.name !== uploadFile.name
  );
  // 如果文件列表为空，则上传服务器按钮不显示
  if (uploadFileList.value.length === 0) {
    uploadFlg.value = false;
  }
};

// 文件批量下载
const downLoadZip = () => {
  ElMessageBox.confirm("确认下载当前选中的图片?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(function () {
    loading.value = true;
    if (fileNames) {
      downLoadZipApi(fileNames)
        .then(() => {
          ElMessage.success("下载完成");
        })
        .finally(() => {
          loading.value = false;
        });
    }
  });
};

onMounted(() => {
  getFileList();
});
</script>
